package com.anjie.powerproject.service.impl;

import com.anjie.powerproject.entity.*;
import com.anjie.powerproject.pojo.CustomAtlasDevice;
import com.anjie.powerproject.pojo.CustomDevice;
import com.anjie.powerproject.pojo.CustomRelationship;
import com.anjie.powerproject.pojo.CustomRelationshipObject;
import com.anjie.powerproject.pojo.dto.RelationshipDTO;
import com.anjie.powerproject.repository.*;
import com.anjie.powerproject.service.RelationshipService;
import com.anjie.powerproject.util.AdjustCoordinator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class RelationshipServiceImpl implements RelationshipService {

    @Autowired
    private RelationshipRepository relationshipRepository;

    @Autowired
    private RelationshipComRepository relationshipComRepository;

    @Autowired
    private DeviceRepository deviceRepository;

    @Autowired
    private EnergyTypeRepository energyTypeRepository;

    @Autowired
    private GraphInfoRepository graphInfoRepository;

    @Autowired
    private GraphDevRepository graphDevRepository;

    @Override
    public Map<String, String> findDeviceInfoByGraphId(Integer graphId) {
        List<Relationship> relationships = relationshipRepository.findRelationshipsByGraphIdEquals(graphId);
        List<CustomAtlasDevice> customAtlasDevices = graphDevRepository.selectAtlasDeviceByGraphId(graphId);
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("edge", relationships.stream().map(item->item.getDeviceFrom()+"#"+item.getDeviceTo()).collect(Collectors.joining(",")));
        resultMap.put("node", customAtlasDevices.stream().map(item->item.getDeviceId()+"").collect(Collectors.joining(",")));
        return resultMap;
    }

    @Override
    public void saveRelationshipList(List list) {
        relationshipRepository.saveAll(list);
    }

    @Override
    public List findRelationshipByFrom(Integer deviceFrom) {
        List<Relationship> relationshipList = relationshipRepository.findRelationshipByFrom(deviceFrom);
        return relationshipList;
    }

    @Override
    public void deleteRelationshipById(Integer relId) {
        relationshipRepository.deleteById(relId);
    }

	 @Override
    public List findAllRelationship() {
        return relationshipRepository.findAll();
    }

     @Override
    public List findCustomRelationship(Integer deviceId) {
        List<CustomRelationship> customRelationships = relationshipRepository.findCustomRelationship(deviceId);
        for (CustomRelationship c:customRelationships){
            EnergyType energyType = energyTypeRepository.findById(c.getTypeId()).orElse(null);
            c.setTypeName(energyType.getTypeName());
        }
        return customRelationships;
    }

    @Override
    public List findCustomRelationshipList() {
        List<Relationship> list = relationshipRepository.findAll();
        List<CustomRelationshipObject> res = new ArrayList<>();
        for (Relationship relationship:list){
            CustomRelationshipObject object = new CustomRelationshipObject();
            Integer deviceFrom = relationship.getDeviceFrom();
            Integer deviceTo = relationship.getDeviceTo();
            int typeId = relationship.getTypeId();
            Integer graphId = relationship.getGraphId();
            object.setId(relationship.getId());
            object.setDeviceFrom(deviceFrom);
            object.setDeviceTo(deviceTo);
            object.setDeviceFromName(deviceRepository.selectCustomDevice(deviceFrom).getDeviceName());
            object.setDeviceToName(deviceRepository.selectCustomDevice(deviceTo).getDeviceName());
            object.setLossRate(relationship.getLossRate());
            object.setTypeId(typeId);
            object.setTypeName(energyTypeRepository.findById(typeId).get().getTypeName());
            object.setGraphId(graphId);
            object.setGraphName(graphInfoRepository.findById(graphId).get().getGraphName());
            object.setStgyCode(relationship.getStgyCode());
            object.setRelName(relationship.getRelName());
            res.add(object);
        }
        return res;
    }

    @Override
    public List<Map> getEdgeByGraphId(Integer graphId) {
        List<Relationship> relationships = relationshipRepository.findRelationshipsByGraphIdEquals(graphId);
        List<CustomAtlasDevice> customAtlasDevices = graphDevRepository.selectAtlasDeviceByGraphId(graphId);
        List<Map> edge = getEdge(relationships, customAtlasDevices);
        return edge;
    }

    private List<Map> getEdge(List<Relationship> relationships,List<CustomAtlasDevice> customAtlasDevices) {
        List<Map> list = new ArrayList<>();
        Iterator<CustomAtlasDevice> customAtlasDeviceIterator = customAtlasDevices.iterator();
        Map<Integer,CustomAtlasDevice> deviceMap = new HashMap<>();
        while (customAtlasDeviceIterator.hasNext()){
            CustomAtlasDevice customAtlasDevice = customAtlasDeviceIterator.next();
            deviceMap.put(customAtlasDevice.getDeviceId(),customAtlasDevice);
        }
        double length = AdjustCoordinator.getLength(customAtlasDevices);
        Iterator<Relationship> iterator = relationships.iterator();
        while (iterator.hasNext()){
            Relationship relationship = iterator.next();
            Map map = new HashMap();
            CustomAtlasDevice fromDevice = deviceMap.get(relationship.getDeviceFrom());
            CustomAtlasDevice toDevice = deviceMap.get(relationship.getDeviceTo());
            float[] fromCoordinate = fromDevice.getCoordinate();
            float[] toCoordinate = toDevice.getCoordinate();
            List adjustList = AdjustCoordinator.adjustByAngle(fromCoordinate[0], fromCoordinate[1], toCoordinate[0], toCoordinate[1], length,length+15,length+15);
            String str = fromDevice.getDeviceId()+"#"+toDevice.getDeviceId();
            EnergyType energyType = energyTypeRepository.findById(relationship.getTypeId()).get();
            map.put("line",adjustList);
            map.put("desc",str);
            map.put("energyPic",energyType.getIconPath());
            map.put("deviceName",Arrays.asList(fromDevice.getDeviceName(),toDevice.getDeviceName()));
            map.put("typeName",energyType.getTypeName());
            list.add(map);
        }
        return list;
    }

    @Override
    public List<CustomRelationshipObject> findCustomRelationshipListByGraphId(Integer graphId) {
        List<Relationship> list = relationshipRepository.findRelationshipsByGraphIdEquals(graphId);
        List<CustomRelationshipObject> res = new ArrayList<>();
        if(list!=null){
            for (Relationship relationship:list){
                CustomRelationshipObject object = new CustomRelationshipObject();
                Integer deviceFrom = relationship.getDeviceFrom();
                Integer deviceTo = relationship.getDeviceTo();
                int typeId = relationship.getTypeId();
                Integer graphId1 = relationship.getGraphId();
                object.setId(relationship.getId());
                object.setDeviceFrom(deviceFrom);
                object.setDeviceTo(deviceTo);
                object.setDeviceFromName(deviceRepository.selectCustomDevice(deviceFrom).getDeviceName());
                object.setDeviceToName(deviceRepository.selectCustomDevice(deviceTo).getDeviceName());
                object.setLossRate(relationship.getLossRate());
                object.setTypeId(typeId);
                object.setTypeName(energyTypeRepository.findById(typeId).get().getTypeName());
                object.setGraphId(graphId1);
                object.setGraphName(graphInfoRepository.findById(graphId).get().getGraphName());
                object.setStgyCode(relationship.getStgyCode());
                object.setRelName(relationship.getRelName());
                object.setExpress(relationship.getExpress());
                object.setTargetResId(relationship.getTargetResId());
                res.add(object);
            }

        }
        return res;
    }

    @Override
    public boolean checkDuplicateRelationship(Relationship relationship) {
        List<Relationship> list = relationshipRepository.findRelationshipsByDeviceFromAndAndDeviceToAndGraphId(relationship.getDeviceFrom(), relationship.getDeviceTo(),relationship.getGraphId());
        if (list==null||list.size()==0)
            return false;
        return true;
    }

    @Override
    public Relationship findRelationshipById(Integer id) {
        return relationshipRepository.findById(id).get();
    }

    @Override
    public Relationship updateRelationship(Relationship relationship) {
        Relationship save = relationshipRepository.save(relationship);
        return save;
    }

    @Override
    public Relationship findRelationshipByFromAndToAndGraphId(Relationship relationship) {
        List<Relationship> list = relationshipRepository.findRelationshipsByDeviceFromAndAndDeviceToAndGraphId(relationship.getDeviceFrom(), relationship.getDeviceTo(), relationship.getGraphId());
        return list==null||list.size()==0?null:list.get(0);
    }

    @Override
    public List getRelationshipListByGraphId(Integer graphId) {
        return relationshipRepository.findRelationshipsByGraphIdEquals(graphId);
    }

    @Override
    public void deleteRelationshipByGraphId(Integer graphId) {
        relationshipRepository.deleteRelationshipsByGraphId(graphId);
    }

    @Override
    public void deleteRelationshipOfDevice(Integer deviceId) {
        List<Relationship> deviceFromEquals = relationshipRepository.findRelationshipsByDeviceFromEquals(deviceId);
        List<Relationship> deviceToEquals = relationshipRepository.findRelationshipsByDeviceToEquals(deviceId);
        if (deviceFromEquals.size()>0){
            relationshipRepository.deleteInBatch(deviceFromEquals);
        }
        if (deviceToEquals.size()>0){
            relationshipRepository.deleteInBatch(deviceToEquals);
        }
    }

    @Override
    public boolean checkStgyCode(String stgyCode){
        List<Relationship> relationships = relationshipRepository.findRelationshipsByStgyCodeEquals(stgyCode);
        if(relationships == null || relationships.size() == 0){
            return true;
        }else {
            return false;
        }
    }

    @Override
    public List findRelationshipByDeviceTo(Integer deviceTo) {
        List<Relationship> relationships = relationshipRepository.findRelationshipsByDeviceToEquals(deviceTo);
        return relationships;
    }

    @Override
    public List findRelationshipByDeviceFrom(Integer deviceFrom) {
        List<Relationship> relationships = relationshipRepository.findRelationshipsByDeviceFromEquals(deviceFrom);
        return relationships;
    }

    @Override
    public List findCustomRelationshipByDeviceFromAndGraphId(Integer deviceTo,Integer graphId) {
        List<Relationship> list = relationshipRepository.findRelationshipsByDeviceToAndGraphId(deviceTo,graphId);
        List<CustomRelationshipObject> res = new ArrayList<>();
        for (Relationship relationship:list){
            CustomRelationshipObject object = new CustomRelationshipObject();
            Integer deviceFrom = relationship.getDeviceFrom();
            int typeId = relationship.getTypeId();
            //Integer graphId = relationship.getGraphId();
            object.setId(relationship.getId());
            object.setDeviceFrom(deviceFrom);
            object.setDeviceTo(deviceTo);
            object.setDeviceFromName(deviceRepository.selectCustomDevice(deviceFrom).getDeviceName());
            object.setDeviceToName(deviceRepository.selectCustomDevice(deviceTo).getDeviceName());
            object.setLossRate(relationship.getLossRate());
            object.setTypeId(typeId);
            object.setTypeName(energyTypeRepository.findById(typeId).get().getTypeName());
            object.setGraphId(graphId);
            object.setGraphName(graphInfoRepository.findById(graphId).get().getGraphName());
            object.setStgyCode(relationship.getStgyCode());
            object.setRelName(relationship.getRelName());
            res.add(object);
        }
        return res;
    }

    @Override
    public List findRelationshipByDeviceFromAndGraphId(Integer deviceFrom, Integer graphId) {
        List list = relationshipRepository.findRelationshipsByDeviceFromAndGraphId(deviceFrom,graphId);
        return  list;
    }

    @Override
    public void deleteRelationshipList(List<Relationship> list){
        if(list != null && list.size()>0){
            for (Relationship r:list){
                relationshipRepository.delete(r);
            }
        }
    }

    @Override
    public CustomRelationshipObject getCustomRelationshipById(Integer id) {
        Relationship relationship = relationshipRepository.findRelationshipById(id);
        if (relationship == null) {
            return null;
        }

        CustomRelationshipObject customRelationship = new CustomRelationshipObject();
        customRelationship.setId(relationship.getId());
        customRelationship.setDeviceFrom(relationship.getDeviceFrom());
        customRelationship.setDeviceTo(relationship.getDeviceTo());
        customRelationship.setDeviceFromName(deviceRepository.selectCustomDevice(relationship.getDeviceFrom()).getDeviceName());
        customRelationship.setDeviceToName(deviceRepository.selectCustomDevice(relationship.getDeviceTo()).getDeviceName());
        return customRelationship;
    }

    @Override
    public List<RelationshipDTO> getall(Integer graphId) {
        List<RelationshipDTO> res = new ArrayList<>();

        // 设备本身其实并不多，还不如一次性全部取过来
        List<Device> devices = deviceRepository.findAll();
        Map<Integer, String> devNameMap = devices.stream().collect(Collectors.toMap(Device::getDeviceId, Device::getDeviceName));

        List<Relationship> rels = relationshipRepository.findRelationshipsByGraphIdEquals(graphId);
        for (Relationship rel : rels) {
            RelationshipDTO r = new RelationshipDTO();
            r.setResId(rel.getId());
            r.setIsCom(0);
            r.setInfo(String.format("[%s] -> [%s]", devNameMap.get(rel.getDeviceFrom()), devNameMap.get(rel.getDeviceTo())));

            res.add(r);
        }

        List<RelationshipCom> relComs = relationshipComRepository.findRelationshipComsByGraphId(graphId);
        Map<Integer, List<RelationshipCom>> relComMap = relComs.stream().collect(Collectors.groupingBy(RelationshipCom::getStgyCode));
        for (Map.Entry<Integer, List<RelationshipCom>> relComEntry : relComMap.entrySet()) {
            RelationshipDTO r = new RelationshipDTO();
            r.setResId(relComEntry.getKey());
            r.setIsCom(1);

            List<RelationshipCom> relComList = relComEntry.getValue();
            String from = relComList.stream().map(e -> devNameMap.getOrDefault(e.getDeviceFrom(), "null")).distinct().collect(Collectors.joining(","));
            String to = relComList.stream().map(e -> devNameMap.getOrDefault(e.getDeviceTo(), "null")).distinct().collect(Collectors.joining(","));
            r.setInfo(String.format("[%s] -> [%s]", from, to));

            res.add(r);
        }

        return res;
    }
}
